#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <unistd.h>
#include <fcntl.h>

int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len) {
	struct flock lock;

	lock.l_type = type;
	lock.l_start = offset;
	lock.l_whence = whence;
	lock.l_len = len;

	return (fcntl(fd, cmd, &flock));
}

pid_t lock_test(int fd, int type, off_t offset, int whence, off_t len) {
	struct flock lock;

	lock.l_type = type;
	lock.l_start = offset;
	lock.l_whence = whence;
	lock.l_len = len;

	if (fcntl(fd, F_GETLK, &lock) < 0) {
		printf("fcntl error\n");
		return -1;
	}

	if (lock.l_type == F_UNLCK)
		return 0;
	else
		return lock.l_pid;
}

#define read_lock(fd, offset, whence, len) \
		lock_reg((fd), F_SETLK, F_RDLCK, (offset), (whence), (len))
#define readw_lock(fd, offset, whence, len) \
		lock_reg((fd), F_SETLKW, F_RDLCK, (offset), (whence), (len))
#define write_lock(fd, offset, whence, len) \
		lock_reg((fd), F_SETLK, F_WRLCK, (offset), (whence), (len))
#define writew_lock(fd, offset, whence, len) \
		lock_reg((fd), F_SETLKW, F_WRLCK, (offset), (whence), (len))
#define un_lock(fd, offset, whence, len) \
		lock_reg((fd), F_SETLK, F_UNLCK, (offset), (whence), (len))

#define is_read_lockable(fd, offset, whence, len) \ 
		(lock_test((fd), F_RDLCK, (offset), (whence), (len)) == 0)
#define is_write_lockable(fd, offset, whence, len) \ 
		(lock_test((fd), F_WRLCK, (offset), (whence), (len)) == 0)

void lockabyte(const char* name, int fd, off_t offset) {
	if (writew_lock(fd, offset, SEEK_SET, 1) < 0) {
		printf("lock error, %s\n", strerror(errno));
		return;
	}

	printf("%s: get lock at byte %ld\n", name, offset);
}

int main() {
	int fd;
	pid_t pid;

	fd = creat("templock", S_IWUSR|S_IRUSR|S_IWGRP|S_IRGRP|S_IWOTH|S_IROTH);
	write(fd, "ab", 2);

	if ((pid=fork()) < 0) {
		printf("fork error\n");
		return -1;
	}
	else if (pid > 0) {
		lockabyte("main", fd, 1);
		sleep(2);
		lockabyte("main", fd, 0);
	}
	else {		
		lockabyte("chld", fd, 0);
		sleep(2);
		lockabyte("chld", fd, 1);
	}
}
